#include "RipRoute.h"

const std::string NextRouteLogFile="route_next.log";
const std::string AllRouteLogFile="route_all.log";

char idToRname[] = "ABCDEF"; //int编号改为字母标号 0-A 1-B 2-C 3-D 4-E 5-F

//时间间隔辅助函数:For Linux time
long long getNowTime()
{ //返回秒数
    //    struct timeval tv;
    //    struct timezone tz;
    //    gettimeofday(&tv, &tz);
    //    return tv.tv_sec; //零头的微秒忽略

    return time((time_t*)NULL);
}

RipRoute::RipRoute(std::string graphName,std::string routeName,bool bNext)
    : bNextRoute(bNext),
      strGraphFileName(graphName),
      strRouteFileName(routeName),
      m_nextfout(NextRouteLogFile,std::ios::app),
      m_allfout(AllRouteLogFile,std::ios::out)
{
    if (!m_allfout || !m_nextfout)
    {
        std::cout << "Fail to Open Route Log File!" << std::endl;
    }

    InitGraph(strGraphFileName);
    InitRoute(strRouteFileName);
}

RipRoute::~RipRoute()
{
    m_nextfout.close();
    m_allfout.close();
}

std::string RipRoute::GetCurrentTime()
{
    time_t timep;
    time (&timep);
    char tmp[64];
    strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S",localtime(&timep) );
    return tmp;
}

void RipRoute::WriteLogtoFile(const std::string& tag,const std::string& value)
{
    (bNextRoute?m_nextfout:m_allfout)<<"[Log] "<<GetCurrentTime()<<" "<<tag<<value<<std::endl;
}

void RipRoute::InitGraph(const std::string& graphFile)
{
    std::ifstream infile(graphFile,std::ios::in);
    if (!infile)
    {
        std::cout << "Fail to Open File!" << std::endl;
        return;
    }
    char v, v1;
    while (infile >> v)
    {
        while (infile >> v1 && v1 != '0')
        {
            ve[v - 'A'].push_back(v1);
        }
    }
    infile.close();
}

void RipRoute::InitRoute(const std::string& routeFile)
{
    std::ifstream infile(routeFile,std::ios::in);
    if (!infile)
    {
        std::cout << "Fail to Open File!" << std::endl;
        return;
    }
    int N;
    char name;
    RIP rp;
    infile >> N;

    for (int i = 0; i < N; i++)
    {
        infile >> name;
        rp.name = name;
        while (infile >> rp.N >> rp.d >> rp.X && rp.N)
        {
            rp.time = getNowTime();
            rip[i].push_back(rp);
        }
    }
    infile.close();
}

void RipRoute::PrintGraph()
{
    std::cout<<"[Log] "<<RipRoute::GetCurrentTime()<<std::endl;
    WriteLogtoFile();
    std::cout<<"**********************网络拓扑结构********************"<<std::endl;
    (bNextRoute?m_nextfout:m_allfout)<<"**********************网络拓扑结构********************"<<std::endl;

    for (int i = 0; i < maxR; i++)
    {
        std::cout << char(i + 'A') << " ";
        (bNextRoute?m_nextfout:m_allfout)<<char(i+'A')<<" ";
        for (int j = 0; j < ve[i].size(); j++)
        {
            std::cout << ve[i][j];
            (bNextRoute?m_nextfout:m_allfout) << ve[i][j];
            if (j < ve[i].size() - 1)
            {
                std::cout << " ";
                (bNextRoute?m_nextfout:m_allfout) << " ";
            }
        }
        std::cout << std::endl;
        (bNextRoute?m_nextfout:m_allfout) << std::endl;
    }
    (bNextRoute?m_nextfout:m_allfout) << std::endl;
}

void RipRoute::PrintRoute()
{
    std::vector<RIP> r;

    for (int i = 0; i < maxR; i++)
    {
        r = rip[i];
        std::cout<<"[Log] "<<RipRoute::GetCurrentTime()<<std::endl;
        WriteLogtoFile();
        std::cout <<"***********************路由表"<<idToRname[i]<<"************************"<<std::endl;
        std::cout <<"到目的网络N\t\t距离D\t下一跳路由器X"<<std::endl;
        (bNextRoute?m_nextfout:m_allfout) <<"***********************路由表"<<idToRname[i]<<"************************"<<std::endl;
        (bNextRoute?m_nextfout:m_allfout) <<"到目的网络N\t\t距离D\t下一跳路由器X"<<std::endl;

        for (int i = 0; i < r.size(); i++)
        {
            std::cout<<"   "<< r[i].N << "\t\t " << r[i].d << "\t    " << r[i].X << std::endl;
            (bNextRoute?m_nextfout:m_allfout)<<"   "<< r[i].N << "\t\t\t " << r[i].d << "\t\t    " << r[i].X << std::endl;
        }
    }
}

std::vector<RIP> RipRoute::Send(std::vector<RIP> r, char c)
{
    for (int i = 0; i < r.size(); i++)
    {
        r[i].d++;
        r[i].X = c;
        r[i].time = getNowTime();
    }
    return r;
}

bool RipRoute::Update()
{
    bool hasEdit = false;
    std::vector<RIP> send;
    std::vector<RIP> rip1[maxR];
    for (int i = 0; i < maxR; i++)
    {
        rip1[i] = rip[i];
    }
    for (int i = 0; i < maxR; i++)
    {
        send = Send(rip[i], i + 'A');

        for (int j = 0; j < ve[i].size(); j++)
        {
            int lid = ve[i][j] - 'A';
            for (int x = 0; x < send.size(); x++)
            {
                int k;
                for (k = 0; k < rip1[lid].size(); k++)
                {
                    if (send[x].N == rip1[lid][k].N)
                    {
                        if (send[x].X == rip1[lid][k].X)
                        {
                            if (rip1[lid][k].d != send[x].d)
                            {
                                rip1[lid][k] = send[x];
                                hasEdit = true;
                            }
                        }
                        else
                        {
                            if (send[x].d < rip1[lid][k].d)
                            {
                                rip1[lid][k] = send[x];
                                hasEdit = true;
                            }
                        }
                        break;
                    }
                }

                if (k == rip1[lid].size())
                {
                    rip1[lid].push_back(send[x]);
                    hasEdit = true;
                }
            }
        }
    }

    for (int i = 0; i < maxR; i++)
    {
        rip[i] = rip1[i];
        std::sort(rip[i].begin(), rip[i].end(), [](RIP r1, RIP r2)->bool
        {
            return r1.N < r2.N;
        });
    }
    return hasEdit;
}

void RipRoute::Check()
{
    auto t1 = getNowTime();
    for (int i = 0; i < maxR; i++)
    {
        for (int j = 0; j < rip[i].size(); j++)
        {
            if (rip[i][j].is_valid && (t1 - rip[i][j].time) > 180)
                rip[i][j].is_valid = false;
            else if (!rip[i][j].is_valid && (t1 - rip[i][j].time) > 120)
                rip[i].erase(rip[i].begin() + j);
        }
    }
}

void RipRoute::printGraphRoute()
{
    PrintGraph();
    PrintRoute();
}

void RipRoute::RunNext()
{
    int T = 0, n = 0;
    ++T;

    std::cout<<std::endl<<"------------------------第"<< T <<"次更新------------------------"<<std::endl;
    (bNextRoute?m_nextfout:m_allfout)<<std::endl<<"------------------------第"<< T <<"次更新------------------------"<<std::endl;
    if (Update())
    {
        PrintRoute();
        n++;
    }
    else
    {
        std::cout<<"[Log] "<<RipRoute::GetCurrentTime()<<std::endl;
        std::cout <<"本次没有任何有价值的修改!说明前面"<< n <<"次修改后,每一个路由器都得到了全局路由信息!"<<std::endl;
        WriteLogtoFile();
        (bNextRoute?m_nextfout:m_allfout) <<"本次没有任何有价值的修改!说明前面"<< n <<"次修改后,每一个路由器都得到了全局路由信息!"<<std::endl;
        return;
    }
    Check();
}

void RipRoute::RunAll()
{
    printGraphRoute();

    int T = 0, n = 0;

    while (true)
    {
        sleep(1); //Linux 单位秒：每隔3秒更新路由表 为了演示运行结果方便不设置为30s秒了
        //Sleep(1000); //Windows 单位毫秒
        ++T;
        std::cout <<std::endl<<"------------------------第"<< T <<"次更新------------------------"<<std::endl;
        m_allfout <<std::endl<<"------------------------第"<< T <<"次更新------------------------"<<std::endl;
        if (Update())
        {
            PrintRoute();
            n++;
        }
        else
        {
            std::cout<<"[Log] "<<RipRoute::GetCurrentTime()<<std::endl;
            std::cout <<"本次没有任何有价值的修改!说明前面"<< n <<"次修改后,每一个路由器都得到了全局路由信息!"<<std::endl;
            WriteLogtoFile();
            m_allfout <<"本次没有任何有价值的修改!说明前面"<< n <<"次修改后,每一个路由器都得到了全局路由信息!"<<std::endl;
            break;
        }
        Check();
    }
}
